package com.nowcoder.topic.dp.hard;

import java.util.ArrayList;

/**
 * NC304 最大子矩阵
 * @author d3y1
 */
public class NC304{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param matrix int整型ArrayList<ArrayList<>>
     * @return int整型
     */
    public int getMaxMatrix (ArrayList<ArrayList<Integer>> matrix) {
        return solution1(matrix);
//        return solution2(matrix);
    }

    /**
     * 动态规划
     *
     * 相似 -> NC302 环形数组的连续子数组最大和
     *
     * dp[k] 表示矩阵从第i行到第j行且以第k列为底(最右列)的子矩阵的最大和
     * sum[k]表示矩阵从第i行到第j行中第k列的元素和
     *
     *         { dp[k-1] + sum[k]  , dp[k-1] > 0  && 1<=i<=n && i<=j<=n && 1<=k<=n
     * dp[k] = {
     *         { sum[k]            , dp[k-1] <= 0 && 1<=i<=n && i<=j<=n && 1<=k<=n
     *
     *            k=2
     *            |
     *         0 -2 -7  0
     * i=2 ->  9  2 -6  2
     *        -4  1 -4  1
     * j=4 -> -1  8  0 -2
     * sum[k]  4 11 -10 1
     * dp[k]   4 15  5  6
     *
     * => result = Math.max(result, dp[k]) = dp[2] = 15
     *
     * @param matrix
     * @return
     */
    private int solution1(ArrayList<ArrayList<Integer>> matrix){
        int n = matrix.size();

        int[] sum,dp;
        int result = Integer.MIN_VALUE;
        for(int i=1; i<=n; i++){
            sum = new int[n+1];
            dp = new int[n+1];
            for(int j=i; j<=n; j++){
                for(int k=1; k<=n; k++){
                    sum[k] += matrix.get(j-1).get(k-1);
                    if(dp[k-1] > 0){
                        dp[k] = dp[k-1] + sum[k];
                    }else{
                        dp[k] = sum[k];
                    }
                    result = Math.max(result, dp[k]);
                }
            }
        }

        return result;
    }

    /**
     * 动态规划
     *
     * dp[i][j]表示从矩阵左上角(1,1)到以位置(i,j)(第i行第j列)为右下角的子矩阵的和
     *
     *            { matrix.get(i-1).get(j-1)                                           , i==1 && j==1
     * dp[i][j] = { dp[i][j-1] + matrix.get(i-1).get(j-1)                              , i==1 && j>1
     *            { dp[i-1][j] + matrix.get(i-1).get(j-1)                              , i>1 && j==1
     *            { dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1] + matrix.get(i-1).get(j-1)  , i>1 && j>1
     *
     *
     * sum表示矩阵中以位置(i,j)(第i行第j列)为左上角且以位置(k,m)(第k行第m列)为右下角的子矩阵的和
     *
     * sum = dp[k][m] - dp[k][j-1] - dp[i-1][m] + dp[i-1][j-1]  , 1<=i<=n && 1<=j<=n && i<=k<=n && j<=m<=n
     *
     * @param matrix
     * @return
     */
    private int solution2(ArrayList<ArrayList<Integer>> matrix){
        int n = matrix.size();

        int[][] dp = new int[n+1][n+1];

        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                if(i==1 && j==1){
                    dp[i][j] = matrix.get(i-1).get(j-1);
                }else if(i==1 && j>1){
                    dp[i][j] = dp[i][j-1] + matrix.get(i-1).get(j-1);
                }else if(i>1 && j==1){
                    dp[i][j] = dp[i-1][j] + matrix.get(i-1).get(j-1);
                }else{
                    dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1] + matrix.get(i-1).get(j-1);
                }
            }
        }

        int result = Integer.MIN_VALUE;
        int sum;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                for(int k=i; k<=n; k++){
                    for(int m=j; m<=n; m++){
                        sum = dp[k][m] - dp[k][j-1] - dp[i-1][m] + dp[i-1][j-1];
                        result = Math.max(result, sum);
                    }
                }
            }
        }

        return result;
    }
}